package info.gridworld.grid;

import java.util.ArrayList;
import java.util.LinkedList;

public class SparseBoundedGrid<E> extends AbstractGrid<E> {
	
	private Object[] occupantRows;
	private int rows;
	private int cols;

	public SparseBoundedGrid(int rows, int cols) {
        if (rows <= 0)
            throw new IllegalArgumentException("rows <= 0");
        if (cols <= 0)
            throw new IllegalArgumentException("cols <= 0");
        
        this.rows = rows;
        this.cols = cols;
        occupantRows = new Object[rows];
        for (int i = 0; i < rows; i++) {
        	LinkedList<OccupantInCol> colList = new LinkedList<OccupantInCol>();
        	occupantRows[i] = colList;
		}        
	}

	@Override
	public int getNumRows() {
		return this.rows;
	}

	@Override
	public int getNumCols() {
		return this.cols;
	}

	@Override
	public boolean isValid(Location loc) {
        return 0 <= loc.getRow() && loc.getRow() < getNumRows()
                && 0 <= loc.getCol() && loc.getCol() < getNumCols();
	}

	@SuppressWarnings("unchecked")
	@Override
	public E put(Location loc, E obj) {
		
		OccupantInCol occupantCol = new OccupantInCol();
		occupantCol.setOccupant(obj);
		occupantCol.setCol(loc.getCol());
		LinkedList<OccupantInCol> rowList = (LinkedList<OccupantInCol>)occupantRows[loc.getRow()];
		E oldObj = this.get(loc);
		rowList.add(occupantCol);
		return oldObj;
	}

	@SuppressWarnings("unchecked")
	@Override
	public E remove(Location loc) {
		LinkedList<OccupantInCol> rowList = (LinkedList<OccupantInCol>)occupantRows[loc.getRow()];
		E oldObj = this.get(loc);
		for (int i = 0; i < rowList.size(); i++) {
			if(rowList.get(i).getCol() == loc.getCol()) {
				rowList.remove(i);
				break;
			}
		}
		return oldObj;
	}

	@SuppressWarnings("unchecked")
	@Override
	public E get(Location loc) {
		LinkedList<OccupantInCol> rowList = (LinkedList<OccupantInCol>)occupantRows[loc.getRow()];
		E obj = null;
		for(OccupantInCol occCol : rowList) {
			if(occCol.getCol() == loc.getCol()) {
				obj = (E)occCol.getOccupant();
				break;
			}
		}
		return obj;
	}

	@SuppressWarnings("unchecked")
	@Override
	public ArrayList<Location> getOccupiedLocations() {
		ArrayList<Location> locs = new ArrayList<Location>();
		for (int i = 0; i < rows; i++) {
			LinkedList<OccupantInCol> rowList = (LinkedList<OccupantInCol>)occupantRows[i];
			for(OccupantInCol occpCol : rowList) {
				locs.add(new Location(i,occpCol.getCol()));
			}
		}
		return locs;
	}

}
